#include "movegen.h "
#include "Node.h"
#include "Engine.h"


Node::~Node(void)
{
}

Node::Node(Move& move, Position& position, int depth)
{
    this->children = NULL;
    this->toBeRemoved = false;
	this->position = position;
    this->depth = depth;
    this->previousMove = move;
	//this->currentScore = 0;
}

Move* Node::GetPreviousMove()
{
    return &previousMove;
}

int Node::GetDepth()
{
    return this->depth;
}

bool Node::IsLeave()
{
    if (children == NULL) return true;
    return children->empty();
}

bool Node::IsCreatedchildren()
{
    return (this->children != NULL);
}


int Node::Createchildren(queue<Node>& nodeQueue){

    if (this->children == NULL)
    {
		this->children = new list<Node*>();
		list<Move> legalMoves;
		GetLegalMoves(position,legalMoves);
		for (list<Move>::iterator move = legalMoves.begin(); move != legalMoves.end(); move++)
		{
            Position* childBoard = new Position(this->position);
            childBoard->Play(*move);
			Node child(*move, *childBoard, this->depth + 1);
			this->children->push_back(&child);
			// critical part
			lock_grab(ChessEngine.nodeQueueLock);
			nodeQueue.push(child);
			lock_release(ChessEngine.nodeQueueLock);
			// critical part end
		}

		// Free memory ???------
		// children are calculated = no more use of current position
		// AlphaBeta is getting score from leaves only	
		//delete &(this->position);

        //System.Console.WriteLine("info depth " + this->depth);
		return legalMoves.size();
    }
    return 0;
}


int Node::GetScore()
{
    return currentScore;
}

// WHITE ALPHABETA
int Node::AlphaBetaWhite(int alpha, int beta, int currentDepth, int maxDepth)
{
    if (currentDepth >= maxDepth || this->IsLeave()) 
		return Evaluate(position);
    int best = MAX_SCORE;
    for (list<Node*>::iterator child = children->begin(); child != children->end(); child++)
	{
		// correction : next ply is black 
        //int score = (*child)->AlphaBetaWhite(-beta, -alpha, currentDepth + 1, maxDepth);
		int score = (*child)->AlphaBetaBlack(-beta, -alpha, currentDepth + 1, maxDepth);
        if (score < best)
        {
            best = score;
            if (best < beta)
            {
                beta = best;
                if (alpha >= beta)
                {
                    return best;
                }
            }
        }
        else
        {
            // active AlphaBeta pruning
            if (currentDepth < (maxDepth - 1)) (*child)->ClearRecursively();
        }
    }

    return best;
}

// WHITE ALPHABETA
int Node::AlphaBetaBlack(int alpha, int beta, int currentDepth, int maxDepth)
{
    if (currentDepth >= maxDepth || this->IsLeave()) 
		return Evaluate(position);

    int best = MIN_SCORE;
    for (list<Node*>::iterator child = children->begin(); child != children->end(); child++)
	{
		// correction : next ply is white 
        //int score = (*child)->AlphaBetaBlack(-beta, -alpha, currentDepth + 1, maxDepth);
		int score = (*child)->AlphaBetaWhite(-beta, -alpha, currentDepth + 1, maxDepth);
        if (score > best)
        {
            best = score;
            if (best > alpha)
            {
                alpha = best;
                if (alpha >= beta)
                {
                    return best;
                }
            }

        }
        else
        {
            // active AlphaBeta pruning
            if (currentDepth < (maxDepth - 1)) (*child)->ClearRecursively();
        }
    }
    return best;
}


void Node::UpdateScore(int maxDepth, bool color)
{
    if (color)
    {
        currentScore = this->AlphaBetaWhite(MIN_SCORE, MAX_SCORE, 1, maxDepth);
    }
    else
    {
        currentScore = this->AlphaBetaBlack(MIN_SCORE, MAX_SCORE, 1, maxDepth);
    }
}

void Node::ClearRecursively()
{
    this->toBeRemoved = true;
    if (this->children != NULL)
    {
		for (list<Node*>::iterator child = children->begin(); child != children->end(); child++)
        {
            (*child)->ClearRecursively();
        }
    }
    this->children = NULL;
}